/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sparql;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Iterator;

import semSimilarity.word.WordSimilarity;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;

/**
 *
 * @author riccardo
 */
public class SparqlWNTest implements WordSimilarity{
	
	private static  SparqlWNTest instance;
	private Model model;
	private HashMap<String,Double> propertiesMap;

    /**
     * @param args the command line arguments
     */
  
  /*  public static void main(String[] args) throws FileNotFoundException {
    	System.out.println(java.lang.Runtime.getRuntime().maxMemory()); 

        Model m=loadModel();
        String test="man;woman";
        while(test !=null && !test.equals("exit")){
   //         test=JOptionPane.showInputDialog("WN");
            if(test !=null && test.contains(";")){
                String[] s=test.split(";");
                printResultQuery(predicatesConnectingTwoTerms(s[0], s[1]),m);
                printResultQuery(oneStepSimilarity(s[0], s[1]),m);
                printResultQuery(twoStepsSimilarity(s[0], s[1]),m);
            }
            
        }
    }
    */
	
	public static SparqlWNTest getInstance(){
	
		if (SparqlWNTest.instance==null)
			instance = new SparqlWNTest();
		
		    return instance;
	}
	
	private SparqlWNTest(){
		this.model = SparqlWNTest.loadModel();
		this.propertiesMap= predicateWeight();
	}
	
	 public  double wordSimilarity(String a, String b, HashMap<String,Double> hm, Model m)  {
		 if(a.equals(b))return 1;
	        return 
	            0.7*pathDistance(executeQuery(predicatesConnectingTwoTerms(a, b),this.model),this.propertiesMap) + 
	            0.2*pathDistance(executeQuery(oneStepSimilarity(a, b), this.model), this.propertiesMap) + 
	            0.1*pathDistance(executeQuery(twoStepsSimilarity(a, b),this.model),this.propertiesMap);
	    }
	
	public static HashMap<String,Double> predicateWeight(){
        HashMap<String,Double> hm = new HashMap<String,Double>();
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/containsWordSense", 1.0);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/derivationallyRelated", 0.8);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/antonymOf", -1.0);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/classifiedByUsage", 0.4);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/hyponymOf", 0.7);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/word", 1.0);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/partMeronymOf", 0.7);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/classifiedByTopic", 0.2);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/similarTo", 0.7);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/attribute", 0.3);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/containsWordSense", 0.7);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/memberMeronymOf", 0.6);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/sameVerbGroupAs", 0.6);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/entails", 0.6);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/participleOf", 0.7);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/causes", 0.4);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/seeAlso", 0.1);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/substanceMeronymOf", 0.8);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/frame", 0.8);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/adverbPertainsTo", 0.7);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/classifiedByRegion", 0.1);
        hm.put("http://www.w3.org/2006/03/wn/wn20/schema/adjectivePertainsTo", 0.8);
        return hm;
    }
	
	 private static Query predicatesConnectingTwoTerms(String s1, String s2){
	        return QueryFactory.create("PREFIX wordnet: <http://www.w3.org/2006/03/wn/wn20/schema/> "
	                +"PREFIX id:   <http://wordnet.rkbexplorer.com/id/> "
	                +"PREFIX rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
	                +"PREFIX dcterms: <http://purl.org/dc/terms/> "
	                +"PREFIX skos: <http://www.w3.org/2004/02/skos/core#> "
	                +"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
	                +"PREFIX owl:  <http://www.w3.org/2002/07/owl#> "
	                +"SELECT DISTINCT ?p WHERE{"
	                + "      {?x rdfs:label '"+s1+"'@en-US . ?y rdfs:label '"+s2+"'@en-US . ?y ?p ?x} "
	                + "UNION {?x rdfs:label '"+s1+"'@en-US . ?y rdfs:label '"+s2+"'@en-US . ?x ?p ?y}} LIMIT 1000");
	    }
	    
	    private static Query oneStepSimilarity(String s1, String s2){
	        return QueryFactory.create("PREFIX wordnet: <http://www.w3.org/2006/03/wn/wn20/schema/> "
	                +"PREFIX id:   <http://wordnet.rkbexplorer.com/id/> "
	                +"PREFIX rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
	                +"PREFIX dcterms: <http://purl.org/dc/terms/> "
	                +"PREFIX skos: <http://www.w3.org/2004/02/skos/core#> "
	                +"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
	                +"PREFIX owl:  <http://www.w3.org/2002/07/owl#> "
	                +"SELECT DISTINCT ?p1 ?p2 WHERE{ "
	                + "     {{ ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?y ?p2 ?z . ?x ?p1 ?z . FILTER(?p1 != rdfs:label && ?p2 != rdfs:label && ?p1 != rdf:type && ?p2 != rdf:type && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}"
	                + "UNION { ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?z ?p2 ?y . ?z ?p1 ?x . FILTER(?p1 != rdfs:label && ?p2 != rdfs:label && ?p1 != rdf:type && ?p2 != rdf:type && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}"
	                + "UNION { ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?z ?p2 ?y . ?x ?p1 ?z . FILTER(?p1 != rdfs:label && ?p2 != rdfs:label && ?p1 != rdf:type && ?p2 != rdf:type && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}"
	                + "UNION { ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?y ?p2 ?z . ?z ?p1 ?x . FILTER(?p1 != rdfs:label && ?p2 != rdfs:label && ?p1 != rdf:type && ?p2 != rdf:type && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}}} LIMIT 1000");
	    }
	    
	    private static Query twoStepsSimilarity(String s1, String s2){
	        return QueryFactory.create("PREFIX wordnet: <http://www.w3.org/2006/03/wn/wn20/schema/> "
	                +"PREFIX id:   <http://wordnet.rkbexplorer.com/id/> "
	                +"PREFIX rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> "
	                +"PREFIX dcterms: <http://purl.org/dc/terms/> "
	                +"PREFIX skos: <http://www.w3.org/2004/02/skos/core#> "
	                +"PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> "
	                +"PREFIX owl:  <http://www.w3.org/2002/07/owl#> "
	                +"SELECT DISTINCT ?p1 ?p3 ?p2 WHERE{ "
	                + "     {{ ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?y ?p2 ?z2 . ?x ?p1 ?z1 . ?z1 ?p3 ?z2 . FILTER(?z2 != ?z1 && ?z2 != ?x && ?z1 != ?y && ?p1 != rdf:type && ?p2 != rdf:type && ?p1 != rdfs:label && ?p2 != rdfs:label && ?p3 != rdfs:label && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p3 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}"
	                + "UNION { ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?z2 ?p2 ?y . ?z1 ?p1 ?x . ?z1 ?p3 ?z2 . FILTER(?z2 != ?z1 && ?z2 != ?x && ?z1 != ?y && ?p1 != rdf:type && ?p2 != rdf:type && ?p1 != rdfs:label && ?p2 != rdfs:label && ?p3 != rdfs:label && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p3 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}"
	                + "UNION { ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?z2 ?p2 ?y . ?x ?p1 ?z1 . ?z1 ?p3 ?z2 . FILTER(?z2 != ?z1 && ?z2 != ?x && ?z1 != ?y && ?p1 != rdf:type && ?p2 != rdf:type && ?p1 != rdfs:label && ?p2 != rdfs:label && ?p3 != rdfs:label && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p3 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}"
	                + "UNION { ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?y ?p2 ?z2 . ?z1 ?p1 ?x . ?z1 ?p3 ?z2 . FILTER(?z2 != ?z1 && ?z2 != ?x && ?z1 != ?y && ?p1 != rdf:type && ?p2 != rdf:type && ?p1 != rdfs:label && ?p2 != rdfs:label && ?p3 != rdfs:label && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p3 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}"
	                + "UNION { ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?y ?p2 ?z2 . ?x ?p1 ?z1 . ?z2 ?p3 ?z1 . FILTER(?z2 != ?z1 && ?z2 != ?x && ?z1 != ?y && ?p1 != rdf:type && ?p2 != rdf:type && ?p1 != rdfs:label && ?p2 != rdfs:label && ?p3 != rdfs:label && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p3 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}"
	                + "UNION { ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?z2 ?p2 ?y . ?z1 ?p1 ?x . ?z2 ?p3 ?z1 . FILTER(?z2 != ?z1 && ?z2 != ?x && ?z1 != ?y && ?p1 != rdf:type && ?p2 != rdf:type && ?p1 != rdfs:label && ?p2 != rdfs:label && ?p3 != rdfs:label && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p3 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}"
	                + "UNION { ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?z2 ?p2 ?y . ?x ?p1 ?z1 . ?z2 ?p3 ?z1 . FILTER(?z2 != ?z1 && ?z2 != ?x && ?z1 != ?y && ?p1 != rdf:type && ?p2 != rdf:type && ?p1 != rdfs:label && ?p2 != rdfs:label && ?p3 != rdfs:label && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p3 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}"
	                + "UNION { ?y rdfs:label '"+s2+"'@en-US . ?x rdfs:label '"+s1+"'@en-US .?y ?p2 ?z2 . ?z1 ?p1 ?x . ?z2 ?p3 ?z1 . FILTER(?z2 != ?z1 && ?z2 != ?x && ?z1 != ?y && ?p1 != rdf:type && ?p2 != rdf:type && ?p1 != rdfs:label && ?p2 != rdfs:label && ?p3 != rdfs:label && ?p1 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p2 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount> && ?p3 != <http://www.w3.org/2006/03/wn/wn20/schema/tagCount>)}}} LIMIT 1000");
	    }
	    
	    private  double pathDistance(QueryExecution qe, HashMap<String,Double> hm){
	        ResultSet rs=qe.execSelect();
	        double ret=0;
	        int normalize=0;
	        while(rs.hasNext()){
	            normalize++;
	            QuerySolution next = rs.next();
	            Iterator<String> varNames = next.varNames();
	            double prod=1;
	            while(varNames.hasNext()){
	                String asd=next.getResource(varNames.next()).toString();
	                //System.out.print(asd+" ");
	                Double d=this.propertiesMap.get(asd);
	                if(d==null){// non dovrebbe dare null pointer exception ma giusto in caso
	                	normalize--;
	                	prod=0;
	                	//System.out.println("non puo entrare qui");
	                	break;
	                }
	                prod=prod*d;
	            }
	            //System.out.println();
	            ret=ret+prod;
	        }
	        if(normalize==0)return 0;
	        ret=ret/normalize;
	        qe.close();
	        return ret;
	    }
    
    public static void printResultQuery(Query query,Model m){
        
            QueryExecution e=QueryExecutionFactory.create(query,m);
                
            ResultSet execSelect = e.execSelect();
            int i=0;
            while(execSelect.hasNext()){
                System.out.println(execSelect.next());
                i++;
            }
            System.out.println(i);
            e.close();
                 
            
    }
    
    public static QueryExecution executeQuery(Query query, Model model){
        QueryExecution ret=QueryExecutionFactory.create(query,model);
        return ret;
    }
    
    public static Model loadModel(){
        try {
            File f=new File(new URI("".getClass().getResource("/wn20full/").toString()));
                Model m=ModelFactory.createDefaultModel();
                
                System.out.println("Loading schema");
                for(File rd: f.listFiles()){
                    System.out.println(rd);
                    Model tot=ModelFactory.createDefaultModel().read(new FileInputStream(rd),"");
                    m.add(tot);
                }
                System.out.println("Loaded");
                return m;
        } catch (FileNotFoundException  ex) {
            
        }catch (  URISyntaxException ex) {
            
        }
        return null;
    }

	@Override
	public double generateWordSimilarity(String s1, String s2) {
		s1 = StringUtility.cleanText(s1);
		s2 = StringUtility.cleanText(s2);
		Double similarity = this.wordSimilarity(s1, s2, null, null);
		
		String strings = s1+" "+s2+" ";
		System.out.println(strings+" "+similarity+" (wordnet)");
		return similarity;
	}
}
